/* main.c -- MQTT client example
 *
 * Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * * Neither the name of Redis nor the names of its contributors may be used
 * to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#include "ets_sys.h"
#include "driver/uart.h"
#include "osapi.h"
#include "mqtt.h"
#include "wifi.h"
#include "config.h"
#include "debug.h"
#include "gpio.h"
#include "user_interface.h"
#include "mem.h"

/******************************************************************************
 * FunctionName : user_rf_cal_sector_set
 * Description  : SDK just reversed 4 sectors, used for rf init data and paramters.
 *                We add this function to force users to set rf cal sector, since
 *                we don't know which sector is free in user's application.
 *                sector map for last several sectors : ABCCC
 *                A : rf cal
 *                B : rf init data
 *                C : sdk parameters
 * Parameters   : none
 * Returns      : rf cal sector
 *******************************************************************************/
MQTT_Client mqttClient;
typedef unsigned long u32_t;
static ETSTimer sntp_timer;
static os_timer_t os_timer;

const uint8_t  Font[][5] = { // char hex ascii number 
{0x00,0x00,0x00,0x00,0x00}, // 0x20 32 0
{0x00,0x00,0x6f,0x00,0x00}, // ! 0x21 33 1
{0x00,0x07,0x00,0x07,0x00}, // " 0x22 34 2
{0x14,0x7f,0x14,0x7f,0x14}, // # 0x23 35 3
{0x00,0x07,0x04,0x1e,0x00}, // $ 0x24 36 4
{0x23,0x13,0x08,0x64,0x62}, // % 0x25 37 5
{0x36,0x49,0x56,0x20,0x50}, // & 0x26 38 6
{0x00,0x00,0x07,0x00,0x00}, // ' 0x27 39 7
{0x00,0x1c,0x22,0x41,0x00}, // ( 0x28 40 8
{0x00,0x41,0x22,0x1c,0x00}, // ) 0x29 41 9
{0x14,0x08,0x3e,0x08,0x14}, // * 0x2a 42 10
{0x08,0x08,0x3e,0x08,0x08}, // + 0x2b 43 11
{0x00,0x50,0x30,0x00,0x00}, // , 0x2c 44 12
{0x08,0x08,0x08,0x08,0x08}, // - 0x2d 45 13
{0x00,0x60,0x60,0x00,0x00}, // . 0x2e 46 14
{0x20,0x10,0x08,0x04,0x02}, // / 0x2f 47 15
{0x3e,0x51,0x49,0x45,0x3e}, // 0 0x30 48 16
{0x00,0x42,0x7f,0x40,0x00}, // 1 0x31 49 17
{0x42,0x61,0x51,0x49,0x46}, // 2 0x32 50 18
{0x21,0x41,0x45,0x4b,0x31}, // 3 0x33 51 19
{0x18,0x14,0x12,0x7f,0x10}, // 4 0x34 52 20
{0x27,0x45,0x45,0x45,0x39}, // 5 0x35 53 21
{0x3c,0x4a,0x49,0x49,0x30}, // 6 0x36 54 22
{0x01,0x71,0x09,0x05,0x03}, // 7 0x37 55 23 
{0x36,0x49,0x49,0x49,0x36}, // 8 0x38 56 24
{0x06,0x49,0x49,0x29,0x1e}, // 9 0x39 57 25
{0x00,0x36,0x36,0x00,0x00}, // : 0x3a 58 26
{0x00,0x56,0x36,0x00,0x00}, // ; 0x3b 59 27
{0x08,0x14,0x22,0x41,0x00}, // < 0x3c 60 28
{0x14,0x14,0x14,0x14,0x14}, // = 0x3d 61 29
{0x00,0x41,0x22,0x14,0x08}, // > 0x3e 62 30
{0x02,0x01,0x51,0x09,0x06}, // ? 0x3f 63 31
{0x3e,0x41,0x5d,0x49,0x4e}, // @ 0x40 64 32
{0x7e,0x09,0x09,0x09,0x7e}, // A 0x41 65 33
{0x7f,0x49,0x49,0x49,0x36}, // B 0x42 66 34
{0x3e,0x41,0x41,0x41,0x22}, // C 0x43 67 35
{0x7f,0x41,0x41,0x41,0x3e}, // D 0x44 68 36
{0x7f,0x49,0x49,0x49,0x41}, // E 0x45 69 37
{0x7f,0x09,0x09,0x09,0x01}, // F 0x46 70 38
{0x3e,0x41,0x49,0x49,0x7a}, // G 0x47 71 39
{0x7f,0x08,0x08,0x08,0x7f}, // H 0x48 72 40
{0x00,0x41,0x7f,0x41,0x00}, // I 0x49 73 41
{0x20,0x40,0x41,0x3f,0x01}, // J 0x4a 74 42
{0x7f,0x08,0x14,0x22,0x41}, // K 0x4b 75 43 
{0x7f,0x40,0x40,0x40,0x40}, // L 0x4c 76 44
{0x7f,0x02,0x0c,0x02,0x7f}, // M 0x4d 77 45
{0x7f,0x04,0x08,0x10,0x7f}, // N 0x4e 78 46
{0x3e,0x41,0x41,0x41,0x3e}, // O 0x4f 79 47
{0x7f,0x09,0x09,0x09,0x06}, // P 0x50 80 48
{0x3e,0x41,0x51,0x21,0x5e}, // Q 0x51 81 49
{0x7f,0x09,0x19,0x29,0x46}, // R 0x52 82 50
{0x46,0x49,0x49,0x49,0x31}, // S 0x53 83 51
{0x01,0x01,0x7f,0x01,0x01}, // T 0x54 84 52
{0x3f,0x40,0x40,0x40,0x3f}, // U 0x55 85 53
{0x0f,0x30,0x40,0x30,0x0f}, // V 0x56 86 54
{0x3f,0x40,0x30,0x40,0x3f}, // W 0x57 87 55
{0x63,0x14,0x08,0x14,0x63}, // X 0x58 88 56
{0x07,0x08,0x70,0x08,0x07}, // Y 0x59 89 57
{0x61,0x51,0x49,0x45,0x43}, // Z 0x5a 90 58
{0x3c,0x4a,0x49,0x29,0x1e}, // [ 0x5b 91 59
{0x02,0x04,0x08,0x10,0x20}, // \ 0x5c 92 60
{0x00,0x41,0x7f,0x00,0x00}, // ] 0x5d 93 61
{0x04,0x02,0x01,0x02,0x04}, // ^ 0x5e 94 62
{0x40,0x40,0x40,0x40,0x40}, // _ 0x5f 95 63
{0x00,0x00,0x03,0x04,0x00}, // ` 0x60 96 64
{0x20,0x54,0x54,0x54,0x78}, // a 0x61 97 65
{0x7f,0x48,0x44,0x44,0x38}, // b 0x62 98 66
{0x38,0x44,0x44,0x44,0x20}, // c 0x63 99 67
{0x38,0x44,0x44,0x48,0x7f}, // d 0x64 100 68
{0x38,0x54,0x54,0x54,0x18}, // e 0x65 101 69
{0x08,0x7e,0x09,0x01,0x02}, // f 0x66 102 70
{0x0c,0x52,0x52,0x52,0x3e}, // g 0x67 103 71
{0x7f,0x08,0x04,0x04,0x78}, // h 0x68 104 72
{0x00,0x44,0x7d,0x40,0x00}, // i 0x69 105 73
{0x20,0x40,0x44,0x3d,0x00}, // j 0x6a 106 74
{0x00,0x7f,0x10,0x28,0x44}, // k 0x6b 107 75
{0x00,0x41,0x7f,0x40,0x00}, // l 0x6c 108 76
{0x7c,0x04,0x18,0x04,0x78}, // m 0x6d 109 77
{0x7c,0x08,0x04,0x04,0x78}, // n 0x6e 110 78
{0x38,0x44,0x44,0x44,0x38}, // o 0x6f 111 79
{0x7c,0x14,0x14,0x14,0x08}, // p 0x70 112 80
{0x08,0x14,0x14,0x18,0x7c}, // q 0x71 113 81
{0x7c,0x08,0x04,0x04,0x08}, // r 0x72 114 82
{0x48,0x54,0x54,0x54,0x20}, // s 0x73 115 83
{0x04,0x3f,0x44,0x40,0x20}, // t 0x74 116 84
{0x3c,0x40,0x40,0x20,0x7c}, // u 0x75 117 85
{0x1c,0x20,0x40,0x20,0x1c}, // v 0x76 118 86
{0x3c,0x40,0x30,0x40,0x3c}, // w 0x77 119 87
{0x44,0x28,0x10,0x28,0x44}, // x 0x78 120 88
{0x0c,0x50,0x50,0x50,0x3c}, // y 0x79 121 89
{0x44,0x64,0x54,0x4c,0x44}, // z 0x7a 122 90
{0x00,0x08,0x36,0x41,0x41}, // { 0x7b 123 91
{0x00,0x00,0x7f,0x00,0x00}, // | 0x7c 124 92
{0x41,0x41,0x36,0x08,0x00}, // } 0x7d 125 93
{0x04,0x02,0x04,0x08,0x04}, // ~ 0x7e 126 94
};

void delay_ms(uint32 x)
{
	for(x=0;x>0;x--)
	{
	  os_delay_us(1000);
	}
}

void POVdisplay (char POVstring[])
{
  uint16_t charSpace = 300; // space between letters
  uint8_t strSpace = 50; // space between repeated string.
  uint8_t length = strlen(POVstring);
  uint8_t pov_data = 0;
  uint8_t led_value[8];
  uint8_t text_num = 0;
	uint8_t col = 0; 
	uint8_t led_num = 0;
	uint32_t i = 0;
  for (text_num = 0; text_num < length; text_num++)
  {
    for (col = 0; col < 5; col++)
    {
      pov_data = Font[POVstring[text_num] - 32][col] ;
      for(led_num = 0; led_num < 8; led_num++)
      {
        
        if(pov_data & 0x80)
        {
          led_value[led_num] = 0;
          //led_on(led_num);
        }
        else {
          led_value[led_num] = 1;
          //led_off(led_num);
        }
        pov_data =pov_data << 1; 
      }
			GPIO_OUTPUT_SET(GPIO_ID_PIN(15), led_value[0]);
			GPIO_OUTPUT_SET(GPIO_ID_PIN(13), led_value[1]); 
			GPIO_OUTPUT_SET(GPIO_ID_PIN(12), led_value[2]); 
			GPIO_OUTPUT_SET(GPIO_ID_PIN(14), led_value[3]); 
			GPIO_OUTPUT_SET(GPIO_ID_PIN(2), led_value[4]); 
			GPIO_OUTPUT_SET(GPIO_ID_PIN(0), led_value[5]); 
			GPIO_OUTPUT_SET(GPIO_ID_PIN(4), led_value[6]);  
			GPIO_OUTPUT_SET(GPIO_ID_PIN(5), led_value[7]); 
      //for(i=0;i < 5900;i++);//字母粗细
			os_delay_us(250);
    }
    GPIO_OUTPUT_SET(GPIO_ID_PIN(0), 1);
		GPIO_OUTPUT_SET(GPIO_ID_PIN(2), 1); 
		GPIO_OUTPUT_SET(GPIO_ID_PIN(4), 1); 
		GPIO_OUTPUT_SET(GPIO_ID_PIN(5), 1); 
		GPIO_OUTPUT_SET(GPIO_ID_PIN(12), 1); 
		GPIO_OUTPUT_SET(GPIO_ID_PIN(13), 1); 
		GPIO_OUTPUT_SET(GPIO_ID_PIN(14), 1);  
		GPIO_OUTPUT_SET(GPIO_ID_PIN(15), 1);//消除单词最后一个字母产生阴影
    os_delay_us(charSpace);
	
  }

  os_delay_us(strSpace);
}

void sntpfn() {
	u32_t ts = 0;
	ts = sntp_get_current_timestamp();
	os_printf("current time : %s\n", sntp_get_real_time(ts));
	if (ts == 0) {
		//os_printf("did not get a valid time from sntp server\n");
	} else {
		os_timer_disarm(&sntp_timer);
		MQTT_Connect(&mqttClient);
	}
}

void wifiConnectCb(uint8_t status) {
	if (status == STATION_GOT_IP) {
		sntp_setservername(0, "pool.ntp.org"); // set sntp server after got ip address
		sntp_init();
		os_timer_disarm(&sntp_timer);
		os_timer_setfn(&sntp_timer, (os_timer_func_t *) sntpfn, NULL);
		os_timer_arm(&sntp_timer, 1000, 1);        //1s
	} else {
		MQTT_Disconnect(&mqttClient);
	}
}

void mqttConnectedCb(uint32_t *args) {
	MQTT_Client* client = (MQTT_Client*) args;
	MQTT_Subscribe(client, "/LED/in", 0);//订阅主题
}

void mqttDisconnectedCb(uint32_t *args) {
	MQTT_Client* client = (MQTT_Client*) args;
	INFO("MQTT: Disconnected\r\n");
}

void mqttPublishedCb(uint32_t *args) {
	MQTT_Client* client = (MQTT_Client*) args;
	INFO("MQTT: Published\r\n");
}
uint8_t pov_date[100] ="Hello POV!";
void mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len,
		uint8_t *data, uint32_t data_len) {

	MQTT_Client* client = (MQTT_Client*) args;

	// // 如果接收到指令是1，GPIO15输出为低,也就是LED开灯，同时发布消息，主题是/LED/out，信息是LED open
	// if (data[0] == '1') {
	// 	MQTT_Publish(client, "/LED/out", "LED open",
	// 			strlen("LED open"), 0, 0);
	// }

	// //如果接收到指令是0，GPIO15为高,也就是LED关灯，同时发布消息，主题是/LED/out，信息是LED off
	// if (data[0] == '0') {
	// 	MQTT_Publish(client, "/LED/out", "LED off",
	// 			strlen("LED off"), 0, 0);
	// }
  
  strcpy(pov_date,data);
	MQTT_Publish(client, "/LED/out", "pov run",
				strlen("pov run"), 0, 0);
	memset(data,0,100);   
}

uint32 ICACHE_FLASH_ATTR
user_rf_cal_sector_set(void) {
	enum flash_size_map size_map = system_get_flash_size_map();
	uint32 rf_cal_sec = 0;

	switch (size_map) {
	case FLASH_SIZE_4M_MAP_256_256:
		rf_cal_sec = 128 - 5;
		break;

	case FLASH_SIZE_8M_MAP_512_512:
		rf_cal_sec = 256 - 5;
		break;

	case FLASH_SIZE_16M_MAP_512_512:
	case FLASH_SIZE_16M_MAP_1024_1024:
		rf_cal_sec = 512 - 5;
		break;

	case FLASH_SIZE_32M_MAP_512_512:
	case FLASH_SIZE_32M_MAP_1024_1024:
		rf_cal_sec = 1024 - 5;
		break;

	default:
		rf_cal_sec = 0;
		break;
	}

	return rf_cal_sec;
}

void POV_Task_Run(void){
   POVdisplay(pov_date);
}

void user_init(void) {

	uart_init(BIT_RATE_115200, BIT_RATE_115200);

	CFG_Load();

  PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0);
	PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
	PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4);
	PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5);
	PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12);
	PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_GPIO13);
	PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, FUNC_GPIO14);
	PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_GPIO15);
	GPIO_OUTPUT_SET(GPIO_ID_PIN(0), 1);
	GPIO_OUTPUT_SET(GPIO_ID_PIN(2), 1); 
	GPIO_OUTPUT_SET(GPIO_ID_PIN(4), 1); 
	GPIO_OUTPUT_SET(GPIO_ID_PIN(5), 1); 
	GPIO_OUTPUT_SET(GPIO_ID_PIN(12), 1); 
	GPIO_OUTPUT_SET(GPIO_ID_PIN(13), 1); 
	GPIO_OUTPUT_SET(GPIO_ID_PIN(14), 1);  
	GPIO_OUTPUT_SET(GPIO_ID_PIN(15), 1);
	MQTT_InitConnection(&mqttClient, sysCfg.mqtt_host, sysCfg.mqtt_port,
			sysCfg.security);
	//MQTT_InitConnection(&mqttClient, "192.168.11.122", 1880, 0);
	MQTT_InitClient(&mqttClient, sysCfg.device_id, sysCfg.mqtt_user,
			sysCfg.mqtt_pass, sysCfg.mqtt_keepalive, 1);
	//MQTT_InitClient(&mqttClient, "client_id", "user", "pass", 120, 1);
	MQTT_InitLWT(&mqttClient, "/lwt", "offline", 0, 0);
	MQTT_OnConnected(&mqttClient, mqttConnectedCb);
	MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb);
	MQTT_OnPublished(&mqttClient, mqttPublishedCb);
	MQTT_OnData(&mqttClient, mqttDataCb);
	WIFI_Connect(sysCfg.sta_ssid, sysCfg.sta_pwd, wifiConnectCb);
	/** 关闭该定时器 */
  os_timer_disarm( &os_timer );
	/** 配置该定时器回调函数 */
	os_timer_setfn( &os_timer, (ETSTimerFunc *) ( POV_Task_Run ), NULL );
	/** 启动该定时器 */
	os_timer_arm( &os_timer, 50, true );

	INFO("\r\nSystem started ...\r\n");

}
